package com.feishi.core.analytic.packing;

import com.feishi.core.util.common.ByteUtil;
import com.feishi.core.util.common.bean.ByteBufferProxy;
import com.feishi.core.analytic.PoType;
import com.feishi.core.analytic.body.AnalyticBody;
import com.feishi.core.analytic.element.AnalyticElement;
import com.feishi.core.analytic.element.AnalyticStaticDataElement;
import com.feishi.core.analytic.element.AnalyticStaticInputDataElement;
import com.feishi.core.analytic.element.AnalyticStaticStartDataElement;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by caixq on 5/4 004.
 */
public class AnalyticUnPacking extends AnalyticPacking{

    private int staticLength;


    public static final int DEFAULT_MODE=0;
    public static final int SPLIT_MODE=1;

    public AnalyticUnPacking(AnalyticBody analyticBody) {
        super(analyticBody);
        build();
    }


    Map<Integer,List<AnalyticElement>> groupElement;

    public void build(){
        groupElement=new HashMap<>();
        this.staticLength=0;
        for (AnalyticElement element:analyticBody.getElements()) {
            initGroupBody(element);
            element.setIndex(staticLength);
            if(element instanceof AnalyticStaticDataElement){
                AnalyticStaticDataElement ele= (AnalyticStaticDataElement) element;
                this.staticLength+=ele.getLength();
            }
        }
    }

    public int getStart(byte[] bytes){
        List<AnalyticElement> list = groupElement.get(PoType.ELEMENT_START);
        int result=-1;
        int index;
        for (AnalyticElement ele:list){
            AnalyticStaticStartDataElement start = (AnalyticStaticStartDataElement) ele;
            byte[] bs=start.getValue();
            index= ByteUtil.indexOf(bytes,bs);
            if(index==-1){
                return -1;
            }else{
                if(result!=-1 && result!=index-start.getIndex()){
                    return -1;
                }
                result=index-start.getIndex();
                if(result<0){
                    return -1;
                }
            }
        }
        return result;
    }

    public byte[] tryToGetBody(ByteBufferProxy bfp) throws IOException {
        switch (analyticBody.unpackingMode){
            case DEFAULT_MODE:
                return tryToGetDefaultBody(bfp);
            case SPLIT_MODE:
                return tryToGetSplitBody(bfp);
            default:
                return tryToGetDefaultBody(bfp);
        }
    }

    private byte[] tryToGetDefaultBody(ByteBufferProxy bfp) {
        int index = getStart(bfp.get());
        if (index == -1) {
            return null;
        }
        bfp.copyToStart(index);
        int contentLength = getContentLength(bfp);
        int bodyLength = contentLength + getStaticLength();
        if(bodyLength<=bfp.getBf().position()){
            byte[] bs= bfp.get(bodyLength);
            bfp.copyToStart(bodyLength);
            return bs;
        }
        return null;
    }

    private byte[] tryToGetSplitBody(ByteBufferProxy bfp) {
        int endIndex=getEndIndex(bfp.get());
       if(endIndex>=0){
           byte[] bs= bfp.get(endIndex);
           bfp.copyToStart(endIndex+1);
           return getByteWithoutEscapeCode(bs,analyticBody.escapeCode);
       }
        return null;
    }

    private int getEndIndex(byte[] bytes){
        return getEndIndex(bytes,analyticBody.escapeCode,analyticBody.separatorCode);
    }
    public static int getEndIndex(byte[] bytes,char escapeCode,char separatorCode) {
        for (int i = 0; i < bytes.length; i++) {
            if(bytes[i]==escapeCode){
                i++;
                continue;
            }

            if(bytes[i]==separatorCode){
                return i;
            }
        }
        return 0;
    }
    public static byte[] getByteWithoutEscapeCode(byte[] bytes,char escapeCode) {
        ByteArrayOutputStream out=new ByteArrayOutputStream();
        int index=0;
        for (int i = 0; i < bytes.length; i++) {
            if(bytes[i]==escapeCode){
                i++;
            }
            bytes[index++]=bytes[i];
        }
        out.write(bytes,0,index);
        return out.toByteArray();
    }

    private int getContentLength(ByteBufferProxy bfp) {
        List<AnalyticElement> list = groupElement.get(PoType.ELEMENT_CONTENT_LENGTH);
        if(list==null||list.size()==0){
            return 0;
        }
        AnalyticStaticInputDataElement element = (AnalyticStaticInputDataElement) groupElement.get(PoType.ELEMENT_CONTENT_LENGTH).get(0);
        int length= (int) element.getValue(bfp);

        return length;
    }


    private void createAnalyticBody(AnalyticElement element) {
    }

    private void initGroupBody(AnalyticElement element) {
        List<AnalyticElement> list = groupElement.get(element.getType());
        if(list==null){
            list=new ArrayList<>();
            groupElement.put(element.getType(),list);
        }
        list.add(element);
    }


    public int getStaticLength() {
        return staticLength;
    }

    public static void main(String[] args) {
        String str="dmsummduakmmsmudhiuwewudsedhniuausds";
        ByteBufferProxy bfp=new ByteBufferProxy();
        bfp.put(str.getBytes());
        byte[] bs=null;
        do{
            int endIndex=getEndIndex(bfp.get(),'m','s');
            if(endIndex>0){
                bs= bfp.get(endIndex);
                bfp.copyToStart(endIndex+1);
                System.out.println();
                System.out.println(new String(bs));
                System.out.println(new String(getByteWithoutEscapeCode(bs,'m')));
            }else{
                bs=null;
            }
        }while (bs!=null);
        System.out.println("end");
    }
}
